home *** CD-ROM | disk | FTP | other *** search
/ The Macintosh Demo Applications CD / Apple-MacintoshDemoApplicationsCD-1.0-1992.iso / More Information / QuicKeys / For Programmers Only.sea / Inside QuicKeys 2™ (v2.1) < prev    next >
Text File  |  1991-06-22  |  24KB  |  564 lines

  1. Inside QuicKeys 2™ Extensions
  2.  
  3. June 1991 Revision
  4.  
  5. Copyright © 1990-91 CE Software, Inc.
  6.  
  7.  
  8. What are Extensions
  9.  
  10. Even though it wasn't designed to do so, the original QuicKeys was extended
  11. by several people to call QuicKeys functions from within their program.
  12. In QuicKeys 2™, not only can an application have QuicKeys 2 perform functions 
  13. for it, but we have taken the idea of extensibility a leap forward and added
  14. what we call extensions.
  15.  
  16. Extensions let you add almost any functionality directly to QuicKeys 2 that will
  17. be available to users in ANY application. To the user, an extension looks and
  18. works just like any other action that QuicKeys 2 can perform, such as a menu
  19. selection or click. Extensions can be defined individually or be part of a
  20. sequence of QuicKeys 2 actions.  And since an extension is in its own file
  21. independent of QuicKeys 2, they can be added or removed without changing
  22. QuicKeys 2.
  23.  
  24. This document provides you with the information you will need to design and
  25. build your own extensions.  On the disk with this document is source for
  26. a sample extension written in C and Pascal.  The function prototypes and
  27. structures discussed in the document are presented in C.  The structures
  28. defined here can be found in extensions.h in the C Examples folder or in
  29. extensions.p in the Pascal Examples folder.  You can also refer to
  30. the source in the Pascal Examples folder for the Pascal declarations of the
  31. functions described here.
  32.  
  33.  
  34. Extension QuicKey Format
  35.  
  36. Each type of action that QuicKeys 2 performs is called a QuicKey.  A QuicKey is
  37. a sequence of bytes that contain the information necessary to perform the action
  38. that is described.  For example, a menu selection QuicKey contains the
  39. information necessary to perform the requested menu selection such as the
  40. menu and item name.  The QuicKey format for an extension is largely up to the
  41. extension developer.  There are only two rules that QuicKeys 2 enforces on an
  42. extension's QuicKey.  The QuicKey must always start with the common data header
  43. called the ExtensionDataHeader and the total length including this header must
  44. not be greater than 2048 bytes.
  45.  
  46. The format of the ExtensionDataHeader is:
  47.  
  48.             struct ExtensionDataHeader {
  49.                 unsigned char    strTitle[16];
  50.                 OSType            ostCreator;
  51.                 short            wLength;
  52.             };
  53.     
  54.     strTitle is the name of the QuicKey.  It's initial value is the name of your
  55.     extension truncated to 15 characters.  Your user interface routine may
  56.     change it.
  57.     
  58.     ostCreator is the extension's creator obtained from it's Finder info by
  59.     QuicKeys 2.  You should not change this field.
  60.     
  61.     wLength is total length of the QuicKey including this header.  The maximum
  62.     length is 2048 bytes.
  63.  
  64.  
  65. Extension Structure
  66.  
  67. Each extension is a separate file in the QuicKeys 2 Extensions folder.  The file
  68. type of each extension must be 'QKex' and the creator must be unique.  QuicKeys 2
  69. uses the creator to find the extension when an extension's QuicKey is being
  70. played. If two extensions with the same creator are present in the Extensions
  71. folder, it's quite likely that a QuicKey for one extension will be executed by
  72. the other extension with "interesting" and possibly spectacular results.
  73.  
  74. CE Software, Inc. will provide a creator registry to ensure that each extension
  75. will have a unique creator.  Once you finish writing your extension you will need
  76. to register your Creator with us.  You can do this by sending a letter, fax,
  77. or electronic message to us at one of the addresses found at the end of this
  78. document.
  79.  
  80. Each extension is divided into two parts.  A user interface routine and an
  81. execution routine.  The user interface routine is used when the user is
  82. defining or editing a QuicKey for your extension in QuicKeys 2.  The
  83. execution routine is generally called when a QuicKey for your extension is
  84. being played by QuicKeys 2.  Your execution routine is also called at certain
  85. other well-defined times and is described in detail below.
  86.  
  87.  
  88. User Interface Routine
  89.  
  90. The user interface part of the extension is stored in a code resource with the
  91. type 'QkyC' and id -14348.  This code resource is loaded when the user is
  92. defining or editing a QuicKey for your extension in QuicKeys 2.  QuicKeys 2
  93. will append your dialog item list (type 'DITL' with id -14348) to the standard
  94. extension edit dialog so you can provide almost any interface you wish.  As
  95. you will see from the description below and in the sample extension on this
  96. disk, writing the user interface part is a lot like writing a control panel.
  97.  
  98. The entry point to the extension is at the beginning of the resource and is:
  99.  
  100.         pascal long ExtensionUI(short wSelector, DialogPtr pDialog,
  101.                 short wHitItem, short wNumItems, ExtensionData* pKeyData,
  102.                 long lRefCon);
  103.  
  104.     wSelector identifies what QuicKeys 2 wants the user interface routine to do.
  105.     Possible values are
  106.         newUI:    You're being called to make a new QuicKey.
  107.                 Initialize your private data accordingly.  Called after your
  108.                 dialog items have been added to QuicKeys 2 dialog but before
  109.                 your initialize call.
  110.  
  111.         initUI:    Called after your dialog items have been added to QuicKeys 2
  112.                 dialog.  Your dialog is still invisible.  You should initialize
  113.                 your dialog items during this call.
  114.  
  115.         hitUI:    The user clicked or typed in one of your items.  The item
  116.                 number is in wHitItem.  Since your dialog items are appended
  117.                 to QuicKeys 2 dialog, you must subtract wNumItems from wHitItem
  118.                 to figure out which of your dialog items were hit.
  119.  
  120.         doneUI:    Called after user selected OK or Cancel. Do any cleanup here.
  121.                 You should always treat your data as if OK was selected.  You
  122.                 are actually working on a copy of your data which will be
  123.                 discarded if cancel is hit.  See pKeyData for more information.
  124.             
  125.     pDialog is the Dialog that QuicKeys 2 will display.
  126.  
  127.     wHitItem is only valid when wSelector is "hit".  It contains the dialog item
  128.     number that the user selected.  You need to subtract wNumItems from this
  129.     value to find out which of your dialog items was hit.
  130.  
  131.     wNumItems contains the number of dialog items in pDialog that belong
  132.     to QuicKeys 2.
  133.  
  134.     pKeyData is the address of a copy of your QuicKey.  It begins with an
  135.     ExtensionDataHeader and is followed by the data for this QuicKey.  Any
  136.     changes made to this copy of your QuicKey are only saved if the user
  137.     selects OK.  If the user selects Cancel, this copy is discarded and 
  138.     your QuicKey is not changed.
  139.  
  140.     lRefCon serves as both return value and storage for your user interface
  141.     routine.  If you return -1, QuicKeys 2 will display an generic edit dialog.
  142.     The value returned by one call to your user interface routine will be passed
  143.     in lRefCon when you are called again. This field works just like cdevValue
  144.     in the control panel programming interface.
  145.  
  146. QuicKeys 2 will display a small icon and extension version information if found
  147. in your file.  The small icon is resource type 'SICN' with id -14348 and version
  148. information is obtained from the resource 'vers' with id 1.
  149.  
  150. Your user interface routine may use any other resources as necessary but to
  151. avoid potential conflicts, their ids should be restricted to -14348 to -14343.
  152.  
  153. Hierarchical Menus
  154.  
  155. If you intend to use hierarchical menus in your extension, you must be careful to
  156. avoid conflicts with any existing menus.  The only way to do this is to find an
  157. unused menu id when creating your hierarchical menu.  If you fail to do this, your
  158. extension will fail to work or, even worse, will adversely affect the application
  159. that the extension was used over.
  160.  
  161. A simple routine to find an available menu id is:
  162.     short
  163.     GetMenuID() {
  164.         short wMenuID = 255;    /* start at biggest valid hierarchical menu id */
  165.         while (wMenuID > 1) {    /* keep trying until we run out of menu ids */
  166.             if (GetMHandle(wMenuID) == nil)        /* if not in use, we're finished */
  167.                 break;
  168.             wMenuID--;        /* try the next id */
  169.             }
  170.         return wMenuID;        /* done.  return the id to the caller */
  171.         }
  172.  
  173. You'd use this routine as follows:
  174.     MenuHandle hPopup = NewMenu(GetMenuID(), "\pmenu");
  175.  
  176. Execution Routine
  177.  
  178. The extension's execution routine is loaded by QuicKeys 2 at boot time and
  179. remains resident in memory.  It is also a code resource in your extension file
  180. of type 'QkyC' with id -14347.  You must remember to set the system heap bit for
  181. this resource so it will be loaded into the system heap (if you don't, you'll
  182. almost certainly cause crashes). 
  183.  
  184. Unlike the user interface routine, the execution routine begins with a structure
  185. that QuicKeys 2 uses to communicate with the extension and the extension can use
  186. to control how QuicKeys 2 calls it.  This structure is part of a linked list of
  187. all extensions currently installed.  The entry point to the extension is
  188. immediately following this structure.
  189.  
  190. The format of this structure is:
  191.             struct ExecuteQueue {
  192.                 ExecuteQueue*    pNext;
  193.                 OSType            ostCreator;
  194.                 unsigned short    flags;
  195.                 unsigned char    strFName[32];
  196.                 char            sicn[32];
  197.                 long            lRefCon;
  198.             };
  199.     
  200.     pNext points to the next extension in the linked list.  It is populated
  201.     by QuicKeys 2.  You should not change this field.
  202.     
  203.     ostCreator is your extension's creator from your Finder info.  It is populated
  204.     by QuicKeys 2.  You should not change this field.  When QuicKeys 2 plays an
  205.     extension's QuicKey, it uses ostCreator to find the execution routine that
  206.     the QuicKey belongs to. 
  207.     
  208.     flags are used to ask QuicKeys 2 for special processing.  See the QuicKeys 2
  209.     header files for the definitions of these flags.  All undefined bits in
  210.     flags are reserved for future use and must be zero. The following bits are
  211.     defined:
  212.     
  213.         PeriodicFlag
  214.  
  215.         The PeriodicFlag bit asks QuicKeys 2 to call you every time
  216.         GetNextEvent or EventAvail are called or when QuicKeys 2 gets time
  217.         during SystemTask.  PeriodicFlag is defined as 0x0001.
  218.     
  219.         AbortFlag
  220.  
  221.         The AbortFlag asks QuicKeys 2 to call you when the user aborts playback
  222.         by clicking the mouse or if QuicKeys 2 aborts playback because of an
  223.         error.  AbortFlag is defined as 0x0002;
  224.                     
  225.         If you are doing something in your extension that expects mouse down
  226.         events (such as displaying a dialog), make sure that AbortFlag is
  227.         off before doing so.  Conversely, AbortFlag should only be on when it
  228.         makes sense to do so.  If you leave AbortFlag on in your extension
  229.         and another extension comes along and expects to see mousedowns, the
  230.         other extension will NOT see mouse down events - even if the other
  231.         extension sets its own AbortFlag to off.  In other words, QuicKeys 2
  232.         will treat mouse down events as aborts if ANY extension has it's
  233.         AbortFlag set.
  234.         
  235.         DontLoadFlag
  236.         
  237.         The DontLoadFlag informs QuicKeys 2 that this extension is not to be
  238.         loaded.  It is useful when you are writing an extension that depends on
  239.         a specific software and/or hardware configuration to be present.  It may
  240.         only be set by your execute routine's InitX call.  If the bit is set, the
  241.         extension will not be displayed in the Define menu nor will users be able
  242.         to edit keys for that extension.  DontLoadFlag is defined as 0x8000.  This
  243.         flag is ignored by versions of QuicKeys 2 prior to 2.1.  See the section
  244.         on "Installation and Availability Control" below for more information.
  245.     
  246.     strFName is your extension's file name.  It is populated by QuicKeys 2.
  247.     You should not change this field.
  248.     
  249.     sicn contains the small icon that QuicKeys 2 displays.  Your executable is
  250.     responsible for populating this field.
  251.     
  252.     lRefCon is available for your extension's use.
  253.  
  254.  
  255. As mentioned earlier, the entry point to your extension is immediately after
  256. the ExecuteQueue structure.  QuicKeys 2 calls your execution routine as:
  257.             
  258.         pascal void Execute(short wSelector, PublicQK2Globals* pQK2Globals);
  259.  
  260.     wSelector identifies the type of call. Possible values are:
  261.  
  262.         initX        Your execution routine was just loaded into the system
  263.                     heap (remember it's during boot time). Initialize private
  264.                     data and the sicn field in your ExecuteQueue header now.
  265.                     This is the only time you're called where your file is open.
  266.  
  267.         regularX    QuicKeys 2 is playing a QuicKey for your extension.  A copy
  268.                     of the QuicKey is in pQK2Globals->ucaCurKey.
  269.  
  270.         periodicX    You have set the PeriodicFlag bit in your ExecuteQueue flags.
  271.                     Register D3 contains the type of periodic call.  Values are:
  272.                         periodicDoRun = SystemTask driver run
  273.                         periodicGNE = GetNextEvent
  274.                         periodicEAvail = EventAvail
  275.                     If you need the periodic type and do not wish to write any
  276.                     assembler code, see the section on commonExecute.a below.
  277.  
  278.         abortX        You have set the AbortFlag bit in your ExecuteQueue flags.
  279.                     You may not move memory during this call.  You should set
  280.                     a flag in your extension to indicate that an abort was
  281.                     caught and turn off AbortFlag.
  282.                     
  283.     pQK2Globals points to QuicKeys 2 globals area.  There are a few fields
  284.     there that may be of interest.  The entire globals area must be
  285.     treated as read only and all undefined areas in it are considered private
  286.     and should not be used.
  287.                     struct PublicQK2Globals {
  288.                         char    private1[524]; 
  289.                         short    wDestVol;
  290.                         long    lDestDirID;
  291.                         long    lPrefsDir;
  292.                         long    lQKDir;
  293.                         long    lKeySetDir;
  294.                         long    lMacroDir;
  295.                         long    lSeqDir;
  296.                         long    lExtDir;
  297.                         long    lClipDir;
  298.                         char    private3[70];    
  299.                         ExecuteQueue* pExtensions;                
  300.                         char    private4[1338];     
  301.                         short    wCurKeyType;
  302.                         char    ucaCurKey[2048];
  303.                         Str255    strTypeString;
  304.                     };
  305.         
  306.         wDestVol contains the refnum of the volume containing QuicKeys 2 (and
  307.         your extension).
  308.         
  309.         lDestDirID is the DirID of the system folder.
  310.         
  311.         lPrefsDir is the DirID of the folder "Preferences" (in the System folder).
  312.         
  313.         lQKDir is the DirID of the folder "QuicKeys Folder" (in the Preferences folder)
  314.  
  315.         lKeySetDir, lMacroDir, lSeqDir, and lClipDir are DirIDs of folders in
  316.         the QuicKeys Folder.  lClipDir contains files used by the Grab Ease™,
  317.         Paste Ease™, and Type Ease™ extensions.
  318.  
  319.         lExtDir contains the DirID of the Extensions directory.  You can use
  320.         wDestVol, lExtDir and fName from the ExecuteQueue to open your
  321.         extension to fetch resources, etc.  The fields here contain DirIDs of
  322.         other folders used by QuicKeys 2.
  323.  
  324.         pExtensions points to the first extension in QuicKeys 2 linked list
  325.         of extensions.
  326.         
  327.         wCurKeyType is the type of QuicKey contained in ucaCurKey.
  328.         
  329.         ucaCurKey contains a copy of the QuicKey currently being played.
  330.         
  331.         strTypeString is the only read/write area available for your use.  If
  332.         you want QuicKeys 2 to type a string for you (as if the user typed it on
  333.         the keyboard), place that string in this field.  Before you copy the string
  334.         into this field, make sure that QuicKeys is not currently typing something
  335.         by looking at strTypeString[0].  Only if that byte is zero, is it safe to
  336.         load this field with the string to type.
  337.  
  338.  
  339. commonExecute.a
  340.  
  341. commonExecute.a is a shortcut provided for creating execution routines in C++,
  342. C, or Pascal.  It avoids the need for you to write assembler code to construct
  343. execution routines.  commonExecute provides space for your ExecuteQueue and
  344. calls your execution routine with the information it is most likely to need.
  345. Think C users can refer to SampleXHdr.c, which provides the same functionality.
  346. commonExecute.a must be linked first so the ExecuteQueue is at the beginning of
  347. the code resource.
  348.  
  349. commonExecute.a expects your routine to be defined as:
  350.  
  351.     pascal void doExecute(short wSelector, ExtensionData* pMyData,
  352.                 ExecuteQueue* pQueue, short wPeriodicType);
  353.  
  354.         wSelector is passed by QuicKeys 2.
  355.         
  356.         pMyData is a pointer to your QuicKey (pQK2Globals->ucaCurKey).
  357.         Remember that it is only valid when wSelector is regularX.
  358.  
  359.         pQueue points to your ExecuteQueue record.
  360.  
  361.         wPeriodicType is only valid when wSelector is periodicX.  It contains
  362.         the type of periodic call.  Possible values are:
  363.                 periodicDoRun = SystemTask driver run
  364.                 periodicGNE = GetNextEvent
  365.                 periodicEAvail = EventAvail
  366.  
  367.  
  368.  
  369. QuicKeys 2 Driver
  370.  
  371. As you might have guessed, QuicKeys 2 installs a driver named ".QuicKeys".
  372. Although you might not need the functionality provided by these documented
  373. calls, they are available for your use. The calls described here are not only
  374. available to extensions but to any application as well.
  375.  
  376. Use OpenDriver to open the QuicKeys 2 driver.  You should never close the
  377. driver.
  378.  
  379. Below is a list of available control calls and their csCode value within parenthesis.
  380.     QK2GetGlobals(8)    Returns a pointer to QuicKeys 2 globals area
  381.                         in csParam.  This area is read-only.
  382.  
  383.     QK2PlayByName(17)    Plays a QuicKey with the given name.  Pass a pointer to
  384.                         the address of the name in csParam.  QuicKeys 2 will first
  385.                         look through the current application's set for the QuicKey.
  386.                         If not found there, the universal set is examined.  If more
  387.                         than one QuicKey with the same name is defined in the same
  388.                         set, you have no guarantee about which one will be played.
  389.                         
  390.                         Here's how you would use the high level Control call to play
  391.                         by name is:
  392.                             StringPtr pName = (StringPtr)"\pQuickPanel";
  393.                             wErr = OpenDriver(QuicKeysDriverName, &wRefNum);
  394.                             wErr = Control(wRefNum, QK2PlayByName, &pName);
  395.                         
  396.                         The corresponding calls using PBControl are:
  397.                             CntrlParam pb;
  398.                             pb.ioCRefNum = wRefNum;
  399.                             pb.csCode = QK2PlayByName;
  400.                             *(char**)&pb.csParam[0] = "\pQuickPanel";
  401.                             wErr = PBControl(&pb, false);
  402.  
  403.                         The corresponding PBControl example in Pascal is:
  404.                             macro: str255;
  405.                             pb: ParamBlockRec;
  406.                             pb.ioCRefNum := wRefNum;
  407.                             pb.csCode := QK2PlayByName;
  408.                             macro := 'QuickPanel';
  409.                             pb.csParam[0] := hiword(longint(@macro));
  410.                             pb.csParam[1] := loword(longint(@macro));
  411.                             wErr := PBControl(@pb, false);
  412.  
  413.                         If no QuicKey with the given name is found, an error is
  414.                         returned.
  415.                         
  416.     QK2PlayByPtr(18)    Plays a QuicKey with the given name.  Pass the key type in
  417.                         the word at csParam.  Pass the address of the QuicKey to
  418.                         play in csParam+2
  419.                         
  420.     QK2GetStatus(19)    Returns the current QuicKeys 2 status.
  421.                         The word at csParam is:
  422.                             0 = idle
  423.                             not 0 = busy
  424.                         The word at csParam + 2 is:
  425.                             QK2IsDisabled = QuicKeys 2 is turned off (see QK2OnOff)
  426.                             QK2InUserInterface = in user interface
  427.                             QK2BusyNotPlaying = busy but not currently playing back
  428.                             QK2IsIdle = idle
  429.                             QK2InPlayFast = in Sequence Playback
  430.                             QK2InPlayFastPaused = paused in Sequence Playback
  431.                             QK2InRecordFast = in Sequence Record
  432.                             QK2InRecordFastPaused = paused in Sequence Record
  433.                             QK2InPlayRT = in Realtime Playback
  434.                             QK2InPlayRTPaused = paused in Realtime Playback
  435.                             QK2InRecordRT = in Realtime Record
  436.                             QK2InRecordRTPaused = paused in Realtime Record
  437.                             
  438.                             QK2IsIdle will be returned if QuicKeys is busy (csParam
  439.                             not 0) but the reason for being busy is not any of the
  440.                             other status codes described above.
  441.  
  442.     QK2Kill(20)            Stops any executing QuicKey or sequence.  If you have
  443.                         paused QuicKeys 2 with a QK2Pause command, you must
  444.                         resume QuicKeys 2 before issuing this command.
  445.  
  446.     QK2OnOff(21)        Pass 0 in the word at csParam to turn QuicKeys 2 on.
  447.                         Pass -1 in the word at csParam to turn QuicKeys 2 off.
  448.  
  449.     QK2Pause(23)        Pass 0 in the word at csParam to pause QuicKeys 2.
  450.                         Pass -1 in the word at csParam to resume QuicKeys 2.
  451.  
  452.                         You could use this so you can do something that
  453.                         QuicKeys 2 might accidentally interpret as something
  454.                         for it to do.
  455.  
  456.     QK2GetPosition(24)    Get the current position in the sequence being played.
  457.                         The longword at csParam contains the position.  An error
  458.                         is returned if QuicKeys 2 is not playing back.
  459.  
  460.     QK2SetPosition(25)    Set the current position in the sequence being played.
  461.                         The longword at csParam contains the new position.  An error
  462.                         is returned if QuicKeys 2 is not playing back.
  463.  
  464.     QK2GetVersion(26)    Returns a long word at csParam that contains the current
  465.                         QuicKeys 2 version.  The format is the same as is stored in
  466.                         the 'vers' id 1 resource.
  467.  
  468. Installation and Availability Control
  469.  
  470. QuicKeys 2 was enhanced in release 2.1 to provide extensions with the ability to
  471. control their installation and whether or not they are available for use.  This
  472. new feature is extremely important when you have an extension that should not be
  473. available to users under certain circumstances (like a System 7 savy extension when
  474. the user is running System 6).
  475.  
  476. A new resource may be added to extensions that will mark them as requiring System 7.
  477. The rez statement for this resource is:
  478.   data 'FLAG' (-14348) {$"8000"};  /* mark extension as requiring System 7 */
  479. Other bits in this resource are reserved for future use and should be zero.
  480.  
  481. If this resource is present and the high order bit is set:
  482.   1) QuicKeys will not load the extension when running under System 6.  Users will
  483.      not be able to define or edit keys for the extension.
  484.   2) QKInstall will not install the extension when running under System 6.
  485.   3) Extension Manager will warn users before installing the extension when running
  486.      under System 6.
  487.  
  488. If the level of control is more sophisticated than just System 6 vs. System 7,
  489. you can perform the necessary tests during the extension's initX routine.  If
  490. the extension is NOT to be loaded, set the DontLoadFlag in the extension's flags
  491. word before returning from your initX routine.  Setting the flag will prevent
  492. users from defining or editing keys for your extension.
  493.  
  494. Both of these schemes are not provided in versions of QuicKeys 2 prior to 2.1.
  495. Versions of QuicKeys 2 prior to 2.1 will always load and display all extensions
  496. present in the extensions folder.
  497.  
  498. Balloon Help
  499.  
  500. Balloon help can be easily added to your extension by following these steps:
  501.  
  502.   1) include BalloonTypes.r in your rez file.
  503.   2) append the following item at the end of your dialog item list:
  504.         {  0,   0,   0,  0}, HelpItem { disabled, HMScanhdlg {-14348} },
  505.   3) add a dialog help resource.  The item in this resource correspond to the
  506.      items in your DITL resource.  See the file Sample.r for a detailed example.
  507.   4) add this snippet of code to your user interface routine's to set the number of
  508.      dialog items to skip field in the dialog help resource:
  509.         Handle hHelp;
  510.         hHelp = GetResource('hdlg', -14348);
  511.         if (hHelp != nil)
  512.             BlockMove((Ptr)&wFirstItem, *hHelp + 2, sizeof(short));
  513.  
  514.  
  515. Extension Resource Summary
  516.  
  517. The resources listed below are the minimal set needed for an extension.
  518. Your extension may use any other resources as necessary but to
  519. avoid potential conflicts, their ids should be restricted to -14348 to -14343.
  520.  
  521. 'vers' (1)                    Version number displayed in user interface dialog
  522. 'DITL' (-14348, Purgeable)    Your dialog items for define/edit dialog
  523. 'hdlg' (-14348)                Balloon help items  (optional)
  524. 'SICN' (-14348)                Small icon for your extension
  525. 'QkyC' (-14348, Purgeable)    User interface routine code
  526. 'QkyC' (-14347, SysHeap)    Execution routine code
  527. 'FLAG' (-14348)                Optional. If present and contains 0x8000, extension only
  528.                             loaded when running System 7.
  529.  
  530. How to reach CE Software, Inc.
  531.  
  532. If you would like to be included in any updates to this document, or need to
  533. ask a question regarding development of extensions, send a message containing
  534. your name, company, title, mailing address, daytime phone number, and electronic
  535. address to us at one of these electronic addresses.
  536.  
  537. America Online:    CESOFTWARE
  538. AppleLink:      CESOFTWARE
  539. CompuServe:      76136,2137
  540. CONNECT:          CESOFTWARE
  541. FAX:              515-224-4534
  542. GEnie:          CESOFTWARE
  543. MCI Mail:        CESOFTWARE
  544. QuickMail:      515-224-1721
  545.  
  546. The first line of the body of your message should read:
  547. ATTN: QuicKeys DS
  548.  
  549. Your message will be forwarded to the correct person and you will receive the
  550. information that you need.
  551.  
  552. If you do not have access to an electronic service, write to:
  553.  
  554. CE Software, Inc.
  555. P.O. Box 65580
  556. West Des Moines, IA  50265
  557. Attn:  QuicKeys Developer Services
  558.  
  559. Free Listing
  560.  
  561. After writing your extension, send us a copy.  We’ll add your extension to a
  562. list of extensions and their authors.  This list will be published electronically
  563. over several well-used services.
  564.